// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.ast.SQLExprImpl;
// import com.alibaba.druid.sql.ast.SQLObject;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;
// import com.alibaba.druid.util.Utils;

// import java.io.IOException;
// import java.math.BigInteger;
// import java.util.Collections;
// import java.util.List;

#include "SQLBinaryExpr.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/doubleEqual.h"
#include "../../../utils/Utils.h"
#include "../../../Exception/FastsqlException.h"

SQLBinaryExpr::SQLBinaryExpr()
{
}

SQLBinaryExpr::SQLBinaryExpr(string_ptr  value)
    : SQLExprImpl()
{

  this->text = value;
}

string_ptr  SQLBinaryExpr::getText()
{
  return text;
}

double SQLBinaryExpr::getValue()
{
  if (text->empty())
  {
    return 0.0;
  }

  if (doubleEqual::AreEqual(val, 0.0))
  {
    long words[text->length() / 64 + 1];
    for (int i = text->length() - 1; i >= 0; --i)
    {
      char ch = text->at(i);
      if (ch == '1')
      {
        int wordIndex = i >> 6;
        words[wordIndex] |= (1L << (text->length() - 1 - i));
      }
    }

    if (sizeof(words) == 1)
    {
      val = words[0];
    }
    else
    {
      char bytes[sizeof(words) * 8];

      for (int i = 0; i < sizeof(words); ++i)
      {
        Utils::putLong(bytes, (sizeof(words) - 1 - i) * 8, words[i]);
      }

      val = atof(bytes);
    }
  }

  return val;
}

void SQLBinaryExpr::setValue(string_ptr  value)
{
  this->text = value;
}

void SQLBinaryExpr::accept0(SQLASTVisitor_ptr visitor)
{
  visitor->visit(SharedObject(SQLBinaryExpr));

  visitor->endVisit(SharedObject(SQLBinaryExpr));
}

void SQLBinaryExpr::output(std::stringstream *  buf)
{
  try
  {
    (*buf)<<"b'";
    (*buf)<<*text;
    (*buf)<<"'";
    // } catch (IOException ex) {
  }
  catch (...)
  {
    // throw new FastsqlException("output error", ex);
    throw new FastsqlException(make_string_ptr("output error"));
  }
}

//@Override
int SQLBinaryExpr::hashCode()
{
  int prime = 31;
  int result = 1;
  // result = prime * result + ((text.empty()) ? 0 : text.hashCode());
  result = prime * result + ((text->empty()) ? 0 : text->length());
  return result;
}

SQLObject_ptr SQLBinaryExpr::clone()
{
  // return new SQLBinaryExpr(text);
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLBinaryExpr>(new SQLBinaryExpr(text));
  std::shared_ptr<SQLBinaryExpr> clone_res = std::dynamic_pointer_cast<SQLBinaryExpr>(clone_tmp);
  return clone_res;
}

//@Override
SQLObject_list_ptr  SQLBinaryExpr::getChildren()
{
  SQLObject_list_ptr  tmp = std::make_shared<std::list<SQLObject_ptr>>();
  return tmp;
}

//@Override
bool SQLBinaryExpr::equals(Object_ptr obj)
{
  if (this == obj.get())
  {
    return true;
  }
  if (obj == nullptr)
  {
    return false;
  }
  if (getClass() != obj->getClass())
  {
    return false;
  }
  std::shared_ptr<SQLBinaryExpr> other = std::dynamic_pointer_cast<SQLBinaryExpr>(obj);
  if (text->empty())
  {
    if (!other->text->empty())
    {
      return false;
    }
  }
  else if (!(text == other->text))
  {
    return false;
  }
  return true;
}
